
import java.awt.Point;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Ant {

    private int x;
    private int y;
    private World world;
    private boolean hasResource;
    private static final Point pN = new Point(0, 1);
    private static final Point pNE = new Point(1, 1);
    private static final Point pE = new Point(1, 0);
    private static final Point pSE = new Point(1, -1);
    private static final Point pS = new Point(0, -1);
    private static final Point pSW = new Point(-1, -1);
    private static final Point pW = new Point(-1, 0);
    private static final Point pNW = new Point(-1, 1);
    private int tired = 0;
    private int totalCost = 0;
    public int antCost_A;
    public int antCost_B;
    private int deathCost;
    private char type;
    private double[] horizontal;
    private double[] vertical;

    private enum direction {

        N, NE, E, SE, S, SW, W, NW
    };

    public Ant(Individual ind, char type) {

        this.type = type;
        if (type == 'a') {
            antCost_A = ind.getAnt_A_Cost();
            deathCost = 2000 * antCost_A;
        } else {
            antCost_B = ind.getAnt_B_Cost();
            deathCost = 2000 * antCost_B;
        }
        horizontal = ind.getHorizontal();
        vertical = ind.getVertical();

    }

    public Ant(Individual ind, int x, int y, char type) {

        this.x = x;
        this.y = y;
        this.type = type;
        if (type == 'a') {
            antCost_A = ind.getAnt_A_Cost();
            deathCost = 2000 * antCost_A;
        } else {
            antCost_B = ind.getAnt_B_Cost();
            deathCost = 2000 * antCost_B;
        }
        horizontal = ind.getHorizontal();
        vertical = ind.getVertical();
    }

    public boolean shouldDie() {
        return (totalCost > deathCost) && !hasResource;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public String toString() {
        if (hasResource) {
            return "ANT: " + x + "," + y + ":" + totalCost;
        } else {
            return "ant: " + x + "," + y + ":" + totalCost;
        }
    }

    void move() {
        if (tired > 0) {
            tired--;
            totalCost++;
            return;
        }
        if (totalCost > deathCost && !hasResource) {
            return;//will be killed
        }


        if (!hasResource) {
            if (type == 'a') {
                hasResource = world.takeResource_A(x, y);
            } else {
                hasResource = world.takeResource_B(x, y);
            }
        }

        if (hasResource) {
            if (type == 'a') {
                world.increase_A_Trail(x, y);
            } else {
                world.increase_B_Trail(x, y);
            }

            if (x == world.COLONY_X && y == world.COLONY_Y) {
                if (type == 'a') {
                    world.returnResources_A();
                } else {
                    world.returnResources_B();
                }
                hasResource = false;
            } else {
                if (x < world.COLONY_X) {
                    x++;
                } else if (x > world.COLONY_X) {
                    x--;
                }

                if (y < world.COLONY_Y) {
                    y++;
                } else if (y > world.COLONY_Y) {
                    y--;
                }
            }
        } else {
            direction d = findDirectionAwayFromColony();
            // System.out.println(d);
            List<Point> pointsToCheck = getForwardPoints(d);
            //System.out.println(pointsToCheck);

            if (x > 0 && x < World.WIDTH - 1 && y > 0 && y < World.HEIGHT - 1) {
                for (Point p : pointsToCheck) {
                    int index;
                    //check for phermone trails
                    if (type == 'a') {
                        index = world.PHEREMONE_A_INDEX;
                    } else {
                        index = world.PHEREMONE_B_INDEX;
                    }
                    if (world.getWorld()[x + p.x][y + p.y][index] > 0) {
                        x += p.x;
                        y += p.y;
                        tired = (int) world.getWorld()[x][y][world.COST_INDEX];
                        return;
                    }
                }
            }
//if no trails present
            double moveHorizontal = Math.random();
            if (moveHorizontal < horizontal[0]) {
                x -= (int) (2 * Math.random()) + 1;
            } else if (moveHorizontal < horizontal[0] + horizontal[1]); else {
                x += (int) (2 * Math.random()) + 1;
            }

            double moveVertical = Math.random();
            if (moveVertical < vertical[0]) {
                y -= (int) (2 * Math.random()) + 1;
            } else if (moveVertical < vertical[0] + vertical[1]); else {
                y += (int) (2 * Math.random()) + 1;
            }
            //x += (int) (Math.random() * 3);
//            y += (int) (Math.random() * 4);
            x = (x + World.WIDTH) % World.WIDTH;
            y = (y + World.HEIGHT) % World.HEIGHT;
            tired = (int) world.getWorld()[x][y][world.COST_INDEX];
        }
    }

    private List<Point> getForwardPoints(direction d) {
        switch (d) {
            case N:
                return Arrays.asList(pN, pNE, pNW, pE, pW);
            case NE:
                return Arrays.asList(pNE, pN, pE, pNW, pSE);
            case E:
                return Arrays.asList(pE, pNE, pSE, pN, pS);
            case SE:
                return Arrays.asList(pSE, pE, pS, pNE, pSW);
            case S:
                return Arrays.asList(pS, pSE, pSW, pE, pW);
            case SW:
                return Arrays.asList(pSW, pS, pW, pSE, pNW);
            case W:
                return Arrays.asList(pW, pSW, pNW, pS, pN);
            case NW:
                return Arrays.asList(pNW, pW, pN, pSW, pNE);
        }

        return Collections.singletonList(pN);
    }

    private direction findDirectionAwayFromColony() {
        int deltaX = x - world.COLONY_X;
        int deltaY = y - world.COLONY_Y;


        if (deltaX == 0 && deltaY == 0) {
            return direction.NE;
        }
        double slope = deltaY * 1.0 / deltaX;
        //      System.out.println("slope: " + slope);
        if (slope > Math.tan(Math.toRadians(45.0 / 2 * 3))) {//N or S
            if (deltaY < 0) {
                return direction.S;
            } else {
                return direction.N;
            }
        } else if (slope > Math.tan(Math.toRadians(45.0 / 2))) {//NE or SW
            if (deltaX < 0) {
                return direction.SW;
            } else {
                return direction.NE;
            }
        } else if (slope > Math.tan(Math.toRadians(-45.0 / 2))) {//E or W
            if (deltaX < 0) {
                return direction.W;
            } else {
                return direction.E;
            }
        } else if (slope > Math.tan(Math.toRadians(-45.0 / 2 * 3))) {//SE or NW
            if (deltaX < 0) {
                return direction.NW;
            } else {
                return direction.SE;
            }
        } else {//N or S
            if (deltaY < 0) {
                return direction.N;
            } else {
                return direction.S;
            }
        }
    }

    void setLocation(World world) {
        this.world = world;
    }
}
